package leetcode.array;

/**
 * @author Cheng Jun
 * Description: 给你一根长度为 n 的绳子，请把绳子剪成整数长度的 m 段（m、n都是整数，n>1并且m>1），
 * 每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少？
 * 例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。
 * <p>
 * 2 <= n , n <= 58
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/jian-sheng-zi-lcof
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 * @version 1.0
 * @date 2022/1/27 14:08
 * 有趣的问题
 */
public class cuttingRope {
    public static void main(String[] args) {
        System.out.println(cuttingRope(58));
        System.out.println(cuttingRope1(58));
    }

    // DP
    // 输入: 2
    // 输出: 1
    // 解释: 2 = 1 + 1, 1 × 1 = 1
    // n>1 并且 m>1，可以随意切成 m 段
    // 这里有个细节，就是如果 i 被切割成 1 和 i-1，那么下次选择的时候，就不能用 res[i]，而是使用 i
    static public int cuttingRope(int n) {
        if (n == 2) return 1;
        if (n == 3) return 2;
        // res[i] 表示长度为i 的绳子最大的乘积
        int[] res = new int[n + 1];
        // 注意：这里需要初始化 res[1] = 1, 表示 长度为 1 的绳子，不切割
        res[1] = 1;
        res[2] = 2;
        res[3] = 3;
        for (int i = 3; i <= n; i++) {
            for (int j = 1; j < i; j++) {
                res[i] = Math.max(res[i], (i - j) * res[j]);
            }
        }
        return res[n];
    }

    // 这里有个细节，就是如果 i 被切割成 1 和 i-1，那么下次选择的时候，就不能用 res[i]，而是使用 i
    static public int cuttingRope1(int n) {
        // res[i] 表示长度为i 的绳子最大的乘积
        int[] res = new int[n + 1];
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j < i; j++) {
                res[i] = Math.max(res[i], Math.max((i - j) * res[j], (i - j) * j));
            }
        }
        return res[n];
    }

    // 还有一种解法：通过数学知识得出结论——尽可能把绳子分成长度为3的小段，这样乘积最大
    // https://leetcode-cn.com/problems/integer-break/solution/zheng-shu-chai-fen-by-leetcode-solution/
}
